home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Snippets / LaunchCreator 1.1 / alias_to_fname.cc next >
C/C++ Source or Header  |  1996-06-08  |  6KB  |  137 lines

  1. /*
  2.  *------------------------------------------------------------------------
  3.         When handling odoc (Open Document), pdoc (Print Document) and
  4. similar AppleEvents, one sometimes needs to know the full directory
  5. path to the document being opened. The "standard" way of going about
  6. this is to obtain FSSpec from the AppleEvent record (or by coercing an
  7. AliasRecord), and use FSSpec's parent directory id to walk up the
  8. folder hierarchy (by repeatedly calling PBGetCatInfoSync())
  9. reconstructing the full path. It works just fine, but kind of tedious:
  10. filling out CInfoPBRec struct is rather messy. Recently I stumbled
  11. upon an easier and shorter way, for a programmer. It's based on two
  12. tricks:
  13.         - AliasRecord gotten from AEDescList of an odoc event record
  14. is a minimal AliasRecord. We need the full record.
  15.         - It's very easy to get volume, folder, file names from the
  16. full AliasRecord. No PBGetCatInfoSync() calls, at least, not by a
  17. programmer.
  18.  
  19.         Again, this technique (code below) would not probably save
  20. too many instructions a CPU has to execute; but it'll definitely help bump
  21. a few lines off the source code. One can also use these tricks to obtain
  22. the full file path from any other AppleEvent pertaining to file(s), or
  23. any AliasRecord or FSSpec for that matter.
  24.  
  25. Converting a minimal alias (say, "pointed" to by an 'alias_handle') to
  26. the full one is a matter of four lines of code:
  27.  
  28.     FSSpec resolved_target;
  29.     Boolean was_changed;
  30.     do_well( ResolveAlias(0,alias_handle,&resolved_target,&was_changed) );
  31.     do_well( UpdateAlias(0,&resolved_target,alias_handle,&was_changed) );
  32.  
  33. The code below defines a function to do the trick, as well as a test
  34. driver to make sure the thing really works.
  35.  
  36. The code has been compiled and tested with CodeWarrior 5-7.
  37. *------------------------------------------------------------------------
  38. */
  39.  
  40. #define RUN_TEST 0
  41.  
  42. #include <string.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <assert.h>
  46.                 // Execute a function 'ex' and make sure
  47.                 // it returns noErr
  48. #define do_well(ex) \
  49.   { OSErr err = (ex); if( err != noErr ) \
  50.     fprintf(stderr,"Failed call " #ex " with error %ld at line %ld of `%s'.", \
  51.     err, __LINE__, __FILE__), exit(4); }
  52.  
  53.  
  54.                 // Get a full path from an alias record
  55.                 // Returns a pointer to a static string
  56.                 // Note, alias has to be a full alias
  57.                 // (minimal alias doesn't have directories record)
  58. const char * get_full_path(AliasHandle alias_handle)
  59. {
  60.   static char path[700];        // Full path to return
  61.   Str63 buffer;
  62.                 // Write a volume name at the beginning of
  63.                 // the path
  64.   do_well( GetAliasInfo(alias_handle,asiVolumeName,buffer) );
  65.   memcpy(path,(char *)buffer+1,buffer[0]);
  66.   char * first_col_pos = path + buffer[0];
  67.   *first_col_pos = ':';         // colon after the volume name
  68.   char * after_ldir_pos = first_col_pos+1;
  69.  
  70.                         // Put directory names from the parent upwards
  71.                         // In the string
  72.                         //      Volume_name:Dir3:Dir2:Dir1:
  73.                         // first_col_pos points to the first : after
  74.                         // the volume name, after_ldir_pos points
  75.                         // after the last column. The new directory
  76.                         // retrieved from the alias record is wedged
  77.                         // between the volume name and first_col_pos
  78.   for(register int dir_level=1;;dir_level++)
  79.   {
  80.     do_well( GetAliasInfo(alias_handle,dir_level,buffer) );
  81.     if( buffer[0] == 0 )
  82.       break;            // no more (grand...dad) directories
  83.                         // Move [after_vname_pos,after_ldir_pos)
  84.                         // chunk forward to make room for this
  85.                         // (grand)parent directory
  86.     char * p = after_ldir_pos;
  87.     char * q = after_ldir_pos += buffer[0]+1;   // reserve space for :
  88.     assert( after_ldir_pos < path + sizeof(path) );
  89.     while( p > first_col_pos )
  90.       *--q = *--p;
  91.     p = (char *)buffer+1+buffer[0];     // End of the (grand)parent dir name
  92.     while( q > first_col_pos+1 )
  93.       *--q = *--p;
  94.   }
  95.                 // Get the file name itself and append it to the
  96.                 // end
  97.   do_well( GetAliasInfo(alias_handle,asiAliasName,buffer) );
  98.   assert( after_ldir_pos+buffer[0]+1 < path + sizeof(path) );
  99.   memcpy(after_ldir_pos,(char *)buffer+1,buffer[0]);
  100.   after_ldir_pos[buffer[0]] = '\0';     // Properly terminate the string
  101.  
  102.   return path;
  103. }
  104.  
  105. #if defined(RUN_TEST) && RUN_TEST
  106.  
  107.             // Test driver
  108.             // Since getting an AppleEvent and taking
  109.             // an AliasRecord from it is a bit of a hassle
  110.             // we use a simpler test: convert a full file
  111.             // name into an alias record, and get it back
  112. void main(void)
  113. {
  114.   FSSpec file_spec;
  115.   do_well(FSMakeFSSpec(0,0,"\pA System:SYSTEM FOLDER:HOSTS",&file_spec));
  116.   AliasHandle alias;        // Pretend this alias is from an AppleEvent
  117.   do_well( NewAliasMinimal(&file_spec,&alias) );
  118.   
  119.               // Now do our trick of turning a min alias to a
  120.               // full one (see comments above). Of course we could've
  121.               // made the full alias right upfront above. But in
  122.               // real applications, an alias from an odoc/pdoc/etc
  123.               // AppleEvent is a min one, and we don't get any choice
  124.   {
  125.     FSSpec resolved_target;
  126.     Boolean was_changed;
  127.     do_well( ResolveAlias(0,alias,&resolved_target,&was_changed) );
  128.     do_well( UpdateAlias(0,&resolved_target,alias,&was_changed) );
  129.   }
  130.   
  131.   printf("\nThe full file name obtained from an alias is '%s'\n",
  132.        get_full_path(alias));
  133.  
  134.   DisposHandle((Handle)alias);
  135. }
  136. #endif
  137.